/////////////////////////////////////////////
//主控键盘的通信模块,kb_net.c
//
////////////////////////////////////////////

#include "keycode.h"

int Udp_Client = -1 ;

//#define LIB

#ifndef LIB
int main(int argc, char **argv)
{

	kb_net_init() ;
	init_camera_monitor();
	
	//网络侦听(Listen)线程
	printf("----------------Keyboard Service Start...\n");
	pthread_t NetListenThreadId = 0;
	pthread_create(&NetListenThreadId, NULL, Raw_Socket, NULL);	

	//初始化监视器轮巡数据
	monitor_run_init()  ;	

	void *ptr;
	pthread_join(NetListenThreadId, &ptr);
	
	printf("----------------Keyboard Service Stop ! \n");
	
	kb_net_exit() ;
		
	exit(0);	
}
#else
pthread_t NetListenThreadId;

int keycode_start()
{
	kb_net_init() ;
	init_camera_monitor();
	
	//网络侦听(Listen)线程
	printf("----------------Keyboard Service Start...\n");
	NetListenThreadId = 0;
	pthread_create(&NetListenThreadId, NULL, Raw_Socket, NULL);	

	//初始化监视器轮巡数据
	monitor_run_init()  ;		
}

int keycode_stop()
{
	exit_thread_keyocde();

	IsListening = FALSE ;

	void *ptr;
	pthread_join(NetListenThreadId, &ptr);
	
	printf("----------------Keyboard Service Stop ! \n");
	
	kb_net_exit() ;
		
	exit(0);
}
#endif

//RAW_SOCKET线程
static void* Raw_Socket(void* pParam)
{
	int i,nRes;
    int ListenSocket, ClientSocket;
	int SocketOptVal = 1;  //SO_REUSEADDR=1,如果端口忙，但TCP状态位于 TIME_WAIT,可以重用端口
	int ret;
	int nAddrLen;
	int KeyHeadLen = 44 ; //键盘数据头长度
	int KeyDataLen  ; //键盘数据长度
	char pKeyDataBuf[KEY_DATA_SIZE] ;
	
    struct sockaddr_in ListenSockAddr, ClientSockAddr;
  
    pthread_detach(pthread_self()) ;
    	
	BYTE * pRecvBuf = malloc(RECV_BUF_SIZE);	
	if(!pRecvBuf)
	{
		printf("---Alloc pRecvBuf failed, no memory !!\n");
		return NULL;
	}
	memset(pRecvBuf,0,RECV_BUF_SIZE) ;
	
	ListenSocket = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); //IPPROTO_IP,IPPROTO_RAW,IPPROTO_TCP,IPPROTO_UDP
	
	if (ListenSocket <0)
	{
		printf("create raw socket error !\n") ;
		return 0 ; 
	}	
	
	const int on = 1 ;
	ret = setsockopt(ListenSocket, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));
	if (ret <0)
	{
		printf("setsockopt(IP_HDRINCL) error !\n") ;
		return 0 ; 
	}	
	
    memset(&ListenSockAddr, 0, sizeof(ListenSockAddr));
    ListenSockAddr.sin_family = AF_INET;
    ListenSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    ListenSockAddr.sin_port = htons(KEY_BORAD_PORT);
	
	ret = bind(ListenSocket, (struct sockaddr *)&ListenSockAddr,  sizeof(struct sockaddr_in));
	if(ret < 0)
	{
		printf("ListenSocket: bind Error!\n");
		pthread_exit(NULL) ;
	}

	IsListening = TRUE ;
 	printf("***************************PID: %d --->Keyboard Listen()\n", getpid());
    while(IsListening)
    {    	    		  
    	nRes = recv(ListenSocket, pRecvBuf , RECV_BUF_SIZE, 0); 	
    	
		if(nRes < 1) //if(nRes == 0 || nRes == -1)
		{
			printf("RecvData_Thread: socket recv error, nRes=%d,socket id=%d\n", nRes,ListenSocket);
			break;// socket error
		}
		else
		{
			//监控键盘数据：IP:20 bytes,TCP:20 bytes,55 aa aa 00 + string1
			if (nRes > KeyHeadLen && pRecvBuf[40] ==0x55 && pRecvBuf[41] ==0xAA && pRecvBuf[42] ==0xAA && pRecvBuf[43] ==0x00)  
			{
				KeyDataLen = nRes - KeyHeadLen ;
				memcpy(&pKeyDataBuf,pRecvBuf + KeyHeadLen, KeyDataLen) ;
				pKeyDataBuf[KeyDataLen]='\0' ;
				
				//处理收到的数据
				ProcessKey(pKeyDataBuf) ; 
				
		/*		
				//for debug begin ///////////////////////////////////
				IP_HEADER *rec_ip = (IP_HEADER *)pRecvBuf;
				struct in_addr addr1 ;
				struct in_addr addr2 ;
				addr1.s_addr = rec_ip->sourceIP ;
				addr2.s_addr = rec_ip->destIP ;	
														
				int i = 0 ;
				for (i=40;i<nRes;i++)
					printf(" %02x", *(pRecvBuf + i) );
					
			
				char s1[20],s2[20];	
				strcpy(s1,(char *)inet_ntoa(addr1)) ;
				strcpy(s2,(char *)inet_ntoa(addr2)) ;
				
				printf("\n src ip=%s,dst ip=%s\n",s1,s2) ;				
				printf("\n") ;	
			*/					
				//for debug end ///////////////////////////////////	

				
			}
		}

    }//while(1)
    

	printf("----- Raw_Socket() Exit !PID=%d\n",getpid());
	free(pRecvBuf);	
	
	pthread_exit(NULL) ;
    return 0;
}

//初始化
int kb_net_init(void)
{
	printf("------------- kb_net_init ---------------\n");
	int i;
	
	if (Udp_Client == -1)
	{
		Udp_Client = socket(AF_INET,SOCK_DGRAM,0) ;
	}	
		
	return TRUE;
}

//通信模块退出
int kb_net_exit(void)
{
	int i;
	
	if (Udp_Client != -1)
	{
		close(Udp_Client) ;
		Udp_Client = -1 ;
	}
	
	return 0 ;
}

//发送数据包
static int Send_NetPacket(const char * DvsIP,WORD DvsPort,TCmdHead * pPacket)
{
	struct hostent *host;
	struct sockaddr_in serv_addr;
	int nRes;
	
	/*地址解析函数*/
	if ((host = gethostbyname(DvsIP)) == NULL)
	{
		printf("gethostbyname error. IP=%s\n",DvsIP);
		return FALSE;
	}
	
	/*设置sockaddr_in 结构体中相关参数*/
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(DvsPort);
	serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
	bzero(&(serv_addr.sin_zero), 8);
	
	nRes = sendto(Udp_Client, pPacket, pPacket->wSize, 0,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
	if(nRes < 1)
	{
		printf("Send_NetPacket: socket send error, nRes=%d!!\n", nRes);		
		
		return FALSE;
	}
	
	return nRes;

}

/*
功能：云台控制
输入：DvsIP-编码器IP，
	  DvsPort-编码器端口
	  ChanNum-编码器通道号
	  ePtzAct-控制类型
	  ActParam-控制参数
返回：0-错误，正数-成功
*/
int PtzControl(const char * DvsIP,WORD DvsPort,BYTE ChanNum,enPtzAction ePtzAct,TPtzActParam ActParam)
{
	int bRet ;
	TReqPtzAct req;
	INIT_NET_PACK(req, CMD_ReqPtzAct);
	req.ChanNum = ChanNum;
	req.ePtzAct = ePtzAct;
	req.ActParam = ActParam ;

	//printf("PtzControl Param1 = %d\n", ActParam.Param1);

	bRet = Send_NetPacket(DvsIP,DvsPort, (TCmdHead*)&req) ;
	
	return bRet ;
}

/*
功能：切换摄像机
  pDecoder：解码器参数
  pEncoder：编码器参数
*/
int SwitchCamera(TDeviceInfo * pDecoder,TDeviceInfo * pEncoder)
{
	int bRet ;
	TReqDecodeSwitch req;
	
	INIT_NET_PACK(req, CMD_ReqDecodeSwitch);
	req.DecChanNum = pDecoder->ChanNum ;  	//解码器通道号
	
	strcpy(req.EncIpAddr,pEncoder->IP);		//编码器IP
	req.EncPort = pEncoder->Port ;			//编码器端口号
	req.EncChanNum = pEncoder->ChanNum ;	//编码器通道号
	strcpy(req.Name,pEncoder->UserName);	//编码器用户名
	strcpy(req.Pswd,pEncoder->Password);	//编码器密码
	
	
	bRet = Send_NetPacket(pDecoder->IP,pDecoder->Port, (TCmdHead*)&req) ;
	
	return bRet ;
}


/*
功能：与编解码器Logout
输入:
	decChanNum：解码器通道号
*/
/*
static int Login(const char * DvsIP,WORD DvsPort,const char * userName,const char * passwd)
{
	TReqLogin req;
	INIT_NET_PACK(req, CMD_ReqLogin);
	req.wClientNetVer = NETWORK_PROTOCOL_VERSION;
	strcpy(req.LoginName, userName);
	strcpy(req.LoginPsw, passwd);
	req.eMonTranMode = 0 ;	

	bRet = Send_NetPacket(DvsIP,DvsPort, (TCmdHead*)&req) ;
	if (!bRet)
	{
		printf("---Login  Error!\n");
		return FALSE;
	}
			
	return TRUE ;	
		
}
*/
/*
功能：与编解码器Logout
输入:
	decChanNum：解码器通道号
*/

/*
static int Logout(const char * DvsIP,WORD DvsPort)
{
	BOOL bRet ;	
	
	TReqLogout req ;
	INIT_NET_PACK((TReqLogout)req, CMD_ReqLogout);
	bRet = Send_NetPacket(DvsIP,DvsPort,(TCmdHead*)&req) ;
	
	printf("---Logout OK !\n");
		
	return bRet ;
}
*/









